package service

import (
	"awesomeProject/app/model"
	"awesomeProject/app/request"
	"awesomeProject/app/response"
	"awesomeProject/global"
	"fmt"
	"github.com/fatih/structs"
	"strconv"
	"strings"
)

type RoleSrv struct{}

// Create 创建
func (r *RoleSrv) Create(req request.RoleCreate, operator model.User) response.Resp {
	insertData := model.RoleFillAble{
		Name:      req.Name,
		Alias:     req.Alias,
		Status:    1,
		Desc:      req.Desc,
		CreatedBy: operator.ID,
		UpdatedBy: operator.ID,
	}
	err := global.Gorm.Model(&model.Role{}).Create(&model.Role{
		RoleFillAble: insertData,
	}).Error
	if err != nil {
		return response.ErrCreate
	}
	return response.OK
}

func (r *RoleSrv) FindByID(id uint) model.Role {
	var role model.Role
	_ = global.Gorm.Where("`id`=?", id).First(&role).Error
	return role
}

func (r RoleSrv) QueryByIds(ids []uint) []model.Role {
	var roles []model.Role
	_ = global.Gorm.Where("id in ?", ids).Find(&roles).Error

	return roles
}

func (r *RoleSrv) FindByAlias(alias string) model.Role {
	var role model.Role
	where := fmt.Sprintf("alias=%s", alias)
	_ = global.Gorm.Where(where).First(&role).Error

	return role
}

// Update 更新
func (r *RoleSrv) Update(id uint, req request.RoleUpdate, operator model.User) response.Resp {
	role := r.FindByID(id)
	if role.ID == 0 {
		return response.ErrRecordNotFound
	}
	req.UpdatedBy = operator.ID
	updates := structs.Map(req)
	if err := global.Gorm.Model(&role).Updates(updates).Error; err != nil {
		return response.ErrUpdate
	}

	return response.OK
}

func (r *RoleSrv) Pagination(req request.RolePagination) response.Resp {
	where := "deleted_at is null"
	if req.Keyword != "" {
		where += " AND (`name` LIKE '%" + req.Keyword + "%' OR `alias` LIKE '%" + req.Keyword + "%') "
	}
	var roles []model.Role
	err := global.Gorm.Where(where).Find(&roles).Error
	if err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}
	var total int64
	err = global.Gorm.Model(&model.Role{}).Count(&total).Error
	if err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}

	return response.OK.WithData(map[string]interface{}{
		"list":  roles,
		"total": total,
	})
}

func (r *RoleSrv) Permissions(id uint) response.Resp {
	role := r.FindByID(id)
	if role.ID == 0 {
		return response.ErrRecordNotFound
	}
	var permissions []model.PermissionWithChecked
	err := global.Gorm.Model(&model.Permission{}).Find(&permissions).Error
	if err != nil {
		return response.ErrQuery
	}

	rolePermissions := sEnforcer.GetFilteredPolicy(0, strconv.Itoa(int(role.ID)))
	for i, permission := range permissions {
		for _, rolePermission := range rolePermissions {
			if permission.Uri == rolePermission[1] && permission.Method == rolePermission[2] {
				permission.Checked = true
			}
		}
		permissions[i] = permission
	}

	return response.OK.WithData(permissions)
}

func (r *RoleSrv) Show(id uint) response.Resp {
	role := r.FindByID(id)
	if role.ID == 0 {
		return response.ErrRecordNotFound
	}

	return response.OK.WithData(role)
}

func (r *RoleSrv) Del(id uint) response.Resp {
	role := r.FindByID(id)
	if role.ID == 0 {
		return response.ErrRecordNotFound
	}
	// 数据删除
	if err := global.Gorm.Unscoped().Delete(&role).Error; err != nil {
		return response.ErrDel.SetMsg("角色删除失败")
	}
	// casbin_rule 删除
	res, _ := sEnforcer.RemoveFilteredPolicy(0, role.Alias)
	if !res {
		return response.ErrDel.SetMsg("casbin_rule 删除失败")
	}
	return response.OK
}

// Menus 角色菜单权限
func (r *RoleSrv) Menus(id uint) response.Resp {
	role := r.FindByID(id)
	if role.ID == 0 {
		return response.ErrRecordNotFound
	}
	var roleMenus []model.RoleMenus
	err := global.Gorm.Where("`role_id`=? and `half_checked`=0", id).Find(&roleMenus).Error
	if err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}
	return response.OK.WithData(roleMenus)
}

// AddMenusForRole 为角色分配菜单权限
func (r *RoleSrv) AddMenusForRole(id uint, checked []uint, halfChecked []uint) response.Resp {
	role := r.FindByID(id)
	if role.ID == 0 {
		return response.ErrRecordNotFound
	}
	// 清空旧关联关系
	delSql := "delete from role_menus where role_id=?"
	err := global.Gorm.Exec(delSql, role.ID).Error
	if err != nil {
		fmt.Println(err)
		return response.ErrQuery.SetMsg(err.Error())
	}
	// 写入新的关联关系
	insertSql := "INSERT INTO `role_menus` (`role_id`, `menu_id`, `half_checked`) VALUES"
	var values []interface{}
	for _, checkedId := range checked {
		insertSql += "(?, ?, ?),"
		values = append(values, role.ID, checkedId, 0)
	}
	for _, halfCheckedId := range halfChecked {
		insertSql += "(?, ?, ?),"
		values = append(values, role.ID, halfCheckedId, 1)
	}
	insertSql = strings.TrimSuffix(insertSql, ",")
	err = global.Gorm.Exec(insertSql, values...).Error
	if err != nil {
		return response.ErrQuery.SetMsg("角色菜单权限分配失败！！！")
	}
	return response.OK
}

func (r *RoleSrv) AllWithChecked() ([]model.Role, error) {
	var roles []model.Role
	err := global.Gorm.Model(&model.Role{}).Find(&roles).Error

	return roles, err
}
